using System.Collections;
using System.Collections.Generic;
using System;
using System.Linq;
using UnityEngine;

namespace PluginPathFinder
{
    public class PathFollower : MonoBehaviour
    {
        public float moveSpeed = 10f;
        public bool alignToPath = true;
        public Transform _transform { get; set; }
        protected List<System.Object> _pathToFollow;
        protected int _currentIndex;

        protected Vector3 CastToVec(System.Object ob)
        {
            if (ob is Vector3)
                return (Vector3)ob;
            return Vector3.zero;
        }

        protected Node CastToNode(System.Object ob)
        {
            if (ob is Node)
            {
                return (Node)ob;
            }
            return null;
        }

        public virtual bool IsOnPoint(int pointIndex)
        {
            return false;
        }
        protected bool IsEndPoint(int pointIndex)
        {
            return pointIndex == EndIndex();
        }


        protected int EndIndex()
        {
            return _pathToFollow.Count - 1;
        }


        protected int GetNextIndex(int currentIndex)
        {
            int nextIndex = -1;
            if (currentIndex < EndIndex()) nextIndex = currentIndex + 1;
            return nextIndex;
        }
        protected int StartIndex() { return 0; }


        // Start is called before the first frame update
        public void Follow(List<System.Object> pointsToFollow, float moveSpeed, bool autoRatate)
        {
            this._pathToFollow = pointsToFollow;
            this.moveSpeed = moveSpeed;
            this.alignToPath = autoRatate;

            StopFollowing();

            _currentIndex = 0;

            StartCoroutine(FollowPath());
        }

        public void Follow(List<Vector3> pointsToFollow, float moveSpeed, bool autoRatate)
        {

            Follow(pointsToFollow.Cast<System.Object>().ToList(), moveSpeed, autoRatate);
        }

        public void Follow(List<Node> pointsToFollow, float moveSpeed, bool autoRatate)
        {
            Follow(pointsToFollow.Cast<System.Object>().ToList(), moveSpeed, autoRatate);
        }
        public void StopFollowing()
        {
            StopAllCoroutines();
        }

        IEnumerator FollowPath()
        {
            yield return null;
            while (true)
            {
                _currentIndex = Mathf.Clamp(_currentIndex, 0, _pathToFollow.Count - 1);

                if (IsOnPoint(_currentIndex))
                {
                    if (IsEndPoint(_currentIndex)) break;
                    else _currentIndex = GetNextIndex(_currentIndex);
                }
                else
                {
                    MoveTo(_currentIndex);
                }

                yield return null;
            }
        }

        public virtual void MoveTo(int pointIndex) { }
    }

}